package glaze.util;
import glaze.mime.BinaryMultipart;
import glaze.mime.TextMultipart;
import glaze.spi.Registry;
import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.http.Consts;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.AbstractContentBody;
import org.apache.http.entity.mime.content.ByteArrayBody;
import org.apache.http.entity.mime.content.ContentBody;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.InputStreamBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.message.BasicNameValuePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Preconditions;
public class FormHelper
{
private interface Converter<T extends AbstractContentBody>
{
T convert(Object bean, Field field, BinaryMultipart ma) throws IllegalArgumentException, IllegalAccessException;
T convert(Object bean, String filename);
}
private static final Logger LOGGER = LoggerFactory.getLogger(FormHelper.class);
private static final Map<Class<?>, Converter<?>> bodies = new HashMap<Class<?>, Converter<?>>();
static {
bodies.put(File.class, new Converter<FileBody>()
{
@Override
public FileBody convert(Object bean, Field field, BinaryMultipart ma) throws IllegalArgumentException,
IllegalAccessException
{
File file = (File) field.get(bean);
return new FileBody(file, ma.mime());
}
@Override
public FileBody convert(Object bean, String filename)
{
return new FileBody((File) bean);
}
});
bodies.put(InputStream.class, new Converter<InputStreamBody>()
{
@Override
public InputStreamBody convert(Object bean, Field field, BinaryMultipart ma) throws IllegalArgumentException,
IllegalAccessException
{
return new InputStreamBody((InputStream) field.get(bean), Preconditions.checkNotNull(ma.fileName(), "Please, set a fileName on @Multipart annotation."), ma.mime());
}
@Override
public InputStreamBody convert(Object bean, String filename)
{
return new InputStreamBody((InputStream) bean, filename);
}
});
bodies.put(byte[].class, new Converter<ByteArrayBody>()
{
@Override
public ByteArrayBody convert(Object bean, Field field, BinaryMultipart ma) throws IllegalArgumentException,
IllegalAccessException
{
return new ByteArrayBody((byte[]) field.get(bean), Preconditions.checkNotNull(ma.fileName(), "Please, set a fileName on @Multipart annotation."), ma.mime());
}
@Override
public ByteArrayBody convert(Object bean, String filename)
{
return new ByteArrayBody((byte[]) bean, filename);
}
});
}
public static MultipartEntity asMultipartEntity(Object bean)
{
MultipartEntity multipartEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
for (Class<?> clz : bodies.keySet()) {
if (bean.getClass().isAssignableFrom(clz)) {
ContentBody body = bodies.get(clz).convert(bean, "file.data");
multipartEntity.addPart("file", body);
return multipartEntity;
}
}
Field[] fields = bean.getClass().getDeclaredFields();
for (Field field : fields) {
addBody(bean, multipartEntity, field);
}
return multipartEntity;
}
public static UrlEncodedFormEntity asUrlEncodedFormEntity(Object bean)
{
return asUrlEncodedFormEntity(bean, Consts.ISO_8859_1);
}
public static UrlEncodedFormEntity asUrlEncodedFormEntity(Object bean, Charset charset)
{
ObjectMapper mapper = Registry.lookup(ObjectMapper.class);
Map<String, String> props = mapper.convertValue(bean, TypeHelper.newMapType(String.class, String.class));
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
for (Map.Entry<String, String> entry : props.entrySet()) {
nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
return new UrlEncodedFormEntity(nvps, charset);
}
private static void addBinBody(Object bean, MultipartEntity multipartEntity, Field field, BinaryMultipart ma)
{
for (Class<?> clz : bodies.keySet()) {
if (field.getType().isAssignableFrom(clz)) {
try {
field.setAccessible(true);
String name = ma.name().isEmpty() ? field.getName() : ma.name();
ContentBody body = bodies.get(clz).convert(bean, field, ma);
multipartEntity.addPart(name, body);
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
} finally {
field.setAccessible(false);
}
break;
}
}
}
private static void addBody(Object bean, MultipartEntity multipartEntity, Field field)
{
BinaryMultipart ma = field.getAnnotation(BinaryMultipart.class);
if (ma != null) {
addBinBody(bean, multipartEntity, field, ma);
} else {
addStringBody(bean, multipartEntity, field);
}
}
private static void addStringBody(Object bean, MultipartEntity multipartEntity, Field field)
{
TextMultipart sa = field.getAnnotation(TextMultipart.class);
if (sa != null) {
try {
field.setAccessible(true);
StringBody body = new StringBody(field.get(bean).toString(), sa.mime(), Charset.forName(sa.charset()));
multipartEntity.addPart(sa.name().isEmpty() ? field.getName() : sa.name(), body);
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
} finally {
field.setAccessible(false);
}
}
}
}